package me.zhengjie.tools.service.impl

import cn.hutool.http.HttpUtil
import cn.hutool.json.JSONUtil
import com.alibaba.fastjson2.JSON
import me.zhengjie.common.exception.BadRequestException

import me.zhengjie.common.utils.*
import me.zhengjie.common.utils.FileUtil.downloadExcel
import me.zhengjie.common.utils.FileUtil.getSize
import me.zhengjie.common.utils.FileUtil.getFileNameNoEx
import me.zhengjie.common.utils.FileUtil.getExtensionName
import me.zhengjie.common.utils.FileUtil.getMd5
import me.zhengjie.common.utils.FileUtil.toFile
import me.zhengjie.tools.service.dto.PictureQueryCriteria
import me.zhengjie.tools.service.PictureService
import me.zhengjie.tools.repository.PictureRepository
import me.zhengjie.tools.domain.Picture
import jakarta.persistence.criteria.CriteriaBuilder
import jakarta.persistence.criteria.CriteriaQuery
import jakarta.persistence.criteria.Root
import jakarta.servlet.http.HttpServletResponse
import org.springframework.cache.annotation.CacheConfig
import org.springframework.cache.annotation.CacheEvict
import org.springframework.cache.annotation.Cacheable
import org.springframework.data.domain.Pageable
import org.springframework.data.jpa.domain.Specification
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Propagation
import org.springframework.transaction.annotation.Transactional
import org.springframework.web.multipart.MultipartFile
import java.io.IOException
import java.util.function.Supplier

/**
 * @author Kuki Wu
 * @date 2018-12-27
 */
@Service(value = "pictureService")
@CacheConfig(cacheNames = ["picture"])
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = [Exception::class])
class PictureServiceImpl(private val pictureRepository: PictureRepository) : PictureService {
    @Cacheable
    override fun queryAll(criteria: PictureQueryCriteria, pageable: Pageable?): Any? {
        return PageUtil.toPage(pictureRepository.findAll(Specification { root: Root<Picture>, criteriaQuery: CriteriaQuery<*>?, criteriaBuilder: CriteriaBuilder ->
            QueryHelp.getPredicate(
                root,
                criteria,
                criteriaBuilder
            )
        }, pageable!!))
    }

    override fun queryAll(criteria: PictureQueryCriteria): List<Picture> {
        return pictureRepository.findAll { root: Root<Picture?>, criteriaQuery: CriteriaQuery<*>?, criteriaBuilder: CriteriaBuilder ->
            QueryHelp.getPredicate(
                root,
                criteria,
                criteriaBuilder
            )
        } as List<Picture>
    }

    @CacheEvict(allEntries = true)
    @Transactional(rollbackFor = [Throwable::class])
    override fun upload(multipartFile: MultipartFile, username: String?): Picture? {
        val file = toFile(multipartFile)
        // 验证是否重复上传
        var picture = pictureRepository.findByMd5Code(
            getMd5(
                file!!
            )
        )
        if (picture != null) {
            return picture
        }
        val paramMap = HashMap<String, Any?>(1)
        paramMap["smfile"] = file
        val result = HttpUtil.post(ElAdminConstant.Url.SM_MS_URL, paramMap)
        val jsonObject = JSONUtil.parseObj(result)
        if (jsonObject[CODE].toString() != SUCCESS) {
            throw BadRequestException(TranslatorUtil.translate(jsonObject[MSG].toString()))
        }
        picture = JSON.parseObject(jsonObject["data"].toString(), Picture::class.java)
        picture.size = getSize(picture.size!!.toLong())
        picture.username = username
        picture.md5Code = getMd5(file)
        picture.filename =
            getFileNameNoEx(multipartFile.originalFilename) + "." + getExtensionName(
                multipartFile.originalFilename
            )
        pictureRepository.save(picture)
        //删除临时文件
        cn.hutool.core.io.FileUtil.del(file)
        return picture
    }

    @Cacheable(key = "#p0")
    override fun findById(id: Long): Picture {
        val picture = pictureRepository.findById(id).orElseGet(Supplier<Picture> { Picture() })!!
        ValidationUtil.isNull(picture.id!!, "Picture", "id", id)
        return picture
    }

    @CacheEvict(allEntries = true)
    @Transactional(rollbackFor = [Exception::class])
    override fun delete(picture: Picture?) {
        try {
            HttpUtil.get(picture!!.delete)
            pictureRepository.delete(picture)
        } catch (e: Exception) {
            pictureRepository.delete(picture!!)
        }
    }

    @CacheEvict(allEntries = true)
    override fun deleteAll(ids: Array<Long>) {
        for (id in ids) {
            delete(findById(id))
        }
    }

    @Throws(IOException::class)
    override fun download(queryAll: List<Picture?>?, response: HttpServletResponse?) {
        val list: MutableList<Map<String?, Any?>?> = ArrayList()
        for (picture in queryAll!!) {
            val map: MutableMap<String?, Any?> = LinkedHashMap()
            map["文件名"] = picture!!.filename
            map["图片地址"] = picture.url
            map["文件大小"] = picture.size
            map["操作人"] = picture.username
            map["高度"] = picture.height
            map["宽度"] = picture.width
            map["删除地址"] = picture.delete
            map["创建日期"] = picture.createTime
            list.add(map)
        }
        downloadExcel(list, response!!)
    }

    companion object {
        private const val SUCCESS = "success"
        private const val CODE = "code"
        private const val MSG = "message"
    }
}